/*
Java board game library.
Copyright (C) 2011  Deepesh Garg

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

package d.g.boardgames.chess;

import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CraftyPositionAnalyser implements PositionAnalyser {

	private String craftyCommand = "crafty" ;
	private int maxWaitTime = 5;
	private int minDepth = 14;
	
	public CraftyPositionAnalyser() {
		maxWaitTime = 5;
		minDepth = 14;
	}
	
	public CraftyPositionAnalyser(int maxWaitTime, int minDepth) {
		this.maxWaitTime = maxWaitTime;
		this.minDepth = minDepth;
	}
	
	public AnalysisData analyse(ChessBoard chessBoard) {
		FENSerializer fenSerializer = new FENSerializer();
		AnalysisData analysisData = new AnalysisData();
		Process process = null;
        try {
        	
            
            process = Runtime.getRuntime().exec (craftyCommand);
            InputStream inputStream = process.getInputStream(); //stream reading from process standard output.
            OutputStream outputStream = process.getOutputStream(); //stream writing to process standard input.
            byte [] buffer = new byte[4096];
            
            
            outputStream.write ("ponder off\n".getBytes()); outputStream.flush();
            outputStream.write ("log off\n".getBytes()); outputStream.flush();
            String fenString = fenSerializer.getString(chessBoard);
            outputStream.write (("setboard " + fenString + "\n").getBytes()); outputStream.flush();
            outputStream.write ("analyze\n".getBytes()); outputStream.flush();
            
            Pattern p = Pattern.compile ("(\\d*)-> *[^ ]* *([^ ]*)(.*)");
            String input = readLine(inputStream);
            while (!input.equals("")) {		    
                Matcher m = p.matcher(input);
                if (m.find()) {
                	System.out.println(input);
                	try {
	                    analysisData.setWhiteScore(Float.parseFloat(m.group(2)));
	                    analysisData.setBlackScore(-analysisData.getWhiteScore());
	                    analysisData.setComment(m.group(3) + " " + readLine(inputStream).trim());
	                    //System.out.println(">>>" + readLine(inputStream));
                	} catch (NumberFormatException nfe) {
                		if (m.group(2).contains("Mat")) {
                			analysisData.setComment(m.group(3) + " " + readLine(inputStream).trim());
                			//System.out.println(">>>" + readLine(inputStream).trim());
                			break;
                		}		                		
                	}
                    if (Integer.parseInt(m.group(1)) >= minDepth) {
                    	break;
                    }
                }
                if (input.contains("book moves")) {
                	analysisData.setComment(input);
                }
                input = readLine(inputStream);
            }
            // Put hint
            if (analysisData.getComment() != null) {
            	String hintPgn = "[FEN \"" + fenString + "\"]\n" + analysisData.getComment();
            	ChessGameData gameData = new ChessGameData();
            	gameData.fromPgn(hintPgn);
            	analysisData.setHint(gameData);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
        	if (process != null) {
            	process.destroy();
            }
        }
        
		return analysisData;
	}
	
	private String readLine(InputStream inputStream) {
		String input = "";
        boolean waitMore = true; int waitCount = 0;
        try {
	        while (inputStream.available() >= 0 && waitMore) {
	        	if (inputStream.available() == 0) {
	        		try {Thread.sleep(1000);} catch (InterruptedException ie) {}
	        		waitCount++;
	        		if (waitCount == maxWaitTime) {
	        			waitMore = false;
	        		}
	        	} else {
	        		waitCount = 0;
	            	int readByte = inputStream.read();
	                input += (char)readByte;
	                if ((char)readByte == '\r' || (char)readByte == '\n') {
	                	break;
	                }
	        	}
	        }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return input;
	}
	
	public void skipContents(InputStream inputStream) throws IOException {
        byte [] buffer = new byte[4096];
        int readBytes = inputStream.read(buffer,0, 1);
        while (inputStream.available() > 0) {
            readBytes = inputStream.read(buffer);
            try {Thread.sleep(100);} catch (InterruptedException ie) {}
        }
        return;
    }
	
	public String getCraftyCommand() {
		return craftyCommand;
	}
	
	public void setCraftyCommand(String craftyCommand) {
		this.craftyCommand = craftyCommand;
	}

	public int getMaxWaitTime() {
		return maxWaitTime;
	}

	public void setMaxWaitTime(int maxWaitTime) {
		this.maxWaitTime = maxWaitTime;
	}

	public int getMinDepth() {
		return minDepth;
	}

	public void setMinDepth(int minDepth) {
		this.minDepth = minDepth;
	}
}
